home *** CD-ROM | disk | FTP | other *** search
- /*
- * SFtoSpr - Star Fighter 3000 graphics converter
- * Graphics conversion routines
- * Copyright (C) 2000 Chris Bazley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public Licence as published by
- * the Free Software Foundation; either version 2 of the Licence, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public Licence
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* ANSI headers */
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <limits.h>
- #include <stdbool.h>
-
- /* RISC OS headers */
- #include "kernel.h"
- #include "swis.h"
- #include "wimplib.h"
-
- /* My library files */
- #include "err.h"
- #include "msgtrans.h"
- #include "SFformats.h"
- #include "SprFormats.h"
- #include "hourglass.h"
- #include "Macros.h"
- #include "flex.h"
- #include "NoBudge.h"
-
- /* Local headers */
- #include "Main.h"
- #include "Utils.h"
- #include "SFgfxconv.h"
-
- /* Sprite output is 8bpp, 45x45 dpi */
- /* Old-style mode number: */
- #define OUTPUT_TYPE_MODE 13
- /* New-style sprite type specifier: */
- #define OUTPUT_TYPE_NEW (1 | (45<<1) | (45<<14) | (4<<27))
-
- /* ----------------------------------------------------------------------- */
- /* Function prototypes */
-
- static int check_spr_type(int type);
-
- /* ----------------------------------------------------------------------- */
- /* Public functions */
-
- int spritehdr_validtile(spriteheader *sph, const char *spritename)
- {
- /* check sprite header (ignore dpi, mask, palette) */
- int tilenum;
- if((sscanf(spritename, "tile_%d", &tilenum) == 1
- /* provide for old style sprite naming */
- || sscanf(spritename, "tile_%d", &tilenum) == 1)
- && sph->width == (SF_MAPTILE_WIDTH/4)-1
- && sph->height == SF_MAPTILE_HEIGHT-1
- && sph->left_bit == 0
- && sph->right_bit == 31
- && check_spr_type(sph->type)
- && tilenum >= 0
- && tilenum <= 254)
- return tilenum;
- else
- return -1;
- }
-
- /* ----------------------------------------------------------------------- */
-
- int spritehdr_validpla(spriteheader *sph, const char *spritename)
- {
- /* check sprite header (ignore dpi, mask, palette) */
- int planetnum;
- if(sscanf(spritename, "planet_%d", &planetnum) == 1
- && sph->width == (SF_PLANET_WIDTH/4)-1
- && sph->height == SF_PLANET_HEIGHT-1
- && sph->left_bit == 0
- && sph->right_bit == 31
- && check_spr_type(sph->type)
- && planetnum >= 0
- && planetnum <= 1)
- return planetnum;
- else
- return -1;
- }
-
- /* ----------------------------------------------------------------------- */
-
- int get_max_tile_num(spriteareaheader **spritearea)
- {
- /* Pre-scan file to find out highest number from all valid tile sprites */
- int max_tilenum;
- spriteheader *input_sprite;
-
- /* we need to multiply by 100 for percentage calculation */
- if(((*spritearea)->sprite_count-1) > (INT_MAX/100))
- M_RETV("TooManySp", -1) /* failure */
-
- max_tilenum = -1; /* could be no valid tile numbers */
- input_sprite = (spriteheader *)((int)(*spritearea) + (*spritearea)->first);
-
- hourglass_on();
- for(int sprite = 0; sprite < (*spritearea)->sprite_count; sprite++) {
- hourglass_percentage((sprite * 100) / (*spritearea)->sprite_count);
-
- /* Check source sprite header */
- char spritename[13];
- strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
- int tilenum = spritehdr_validtile(input_sprite, spritename);
- if(tilenum > max_tilenum)
- max_tilenum = tilenum;
-
- /* Calculate address of next sprite */
- input_sprite = (spriteheader *)((int)input_sprite+input_sprite->size);
- } /* next sprite */
- hourglass_off();
-
- return max_tilenum;
- }
-
- /* ----------------------------------------------------------------------- */
-
- int get_max_planet_num(spriteareaheader **spritearea)
- {
- /* Pre-scan file to find out highest number from all valid planet sprites */
- int max_planetnum;
- spriteheader *input_sprite;
-
- /* we need to multiply by 100 for percentage calculation */
- if(((*spritearea)->sprite_count-1) > (INT_MAX/100))
- M_RETV("TooManySp", -1) /* failure */
-
- max_planetnum = -1; /* could be no valid planet numbers */
- input_sprite = (spriteheader *)((int)(*spritearea) + (*spritearea)->first);
-
- hourglass_on();
- for(int sprite = 0; sprite < (*spritearea)->sprite_count; sprite++) {
- hourglass_percentage((sprite * 100) / (*spritearea)->sprite_count);
-
- /* Check source sprite header */
- char spritename[13];
- strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
- int planetnum = spritehdr_validpla(input_sprite, spritename);
- if(planetnum > max_planetnum)
- max_planetnum = planetnum;
-
- /* Calculate address of next sprite */
- input_sprite = (spriteheader *)((int)input_sprite+input_sprite->size);
- } /* next sprite */
- hourglass_off();
-
- return max_planetnum;
- }
-
-
- /* ----------------------------------------------------------------------- */
-
- bool sprites_to_tiles(spriteareaheader **spritearea, SF_MapTilesSetHdr **ret_tileset, bool abandon_on_dud)
- {
- /*
- rewritten 19/07/2000 to cope with out-of-order and inappropriate sprites
- rewritten 20/07/2000 to cope with sprites wanting to be bigger tile numbers than the number of sprites in the file
- 24.04.01 - eliminated hugely nested error handlers
- - header to write is now a parameter
- - no longer returns an error pointer
- 10.05.01 returns code indicating success
- new param 'abandon_on_dud' controls behaviour with dud sprites
- 05.06.01 removed (excessive?) memory checking
- 11.06.01 queries dud sprites during prescan, blanks free header word, can create empty tiles files
- 16.09.01 No longer writes header info (not available until read from window)
- areasize eliminated as a parameter - not needed if no checks
- 02.11.01 Copes properly with funny sized header on input sprite area
- Made parameters strongly typed
- now returns an error block rather than 0 for fail
- 16.12.01 input and output blocks are both flexlib.
- 05.05.02 static pointers to flex blocks
- more scopes to help register allocation
- 20.11.02 eliminated floats from hourglass percentage calculation
- 05.09.03 fixed memory leak of ret_tileset on error
- */
-
- SF_MapTilesSetHdr *ret_tileset_ptr;
- int max_tilenum;
- /* pointers to write new tile and start of source sprite */
-
- max_tilenum = get_max_tile_num(spritearea);
- if(max_tilenum == -1)
- return false; /* failure */
-
- /* Allocate memory for tile area */
- if(!flex_alloc((flex_ptr)ret_tileset, sizeof(SF_MapTilesSetHdr) + (sizeof(SF_MapTile)*(max_tilenum+1))))
- MG_RETV("NoMem", false) /* failure */
-
- nobudge_register(1024);
- ret_tileset_ptr = *ret_tileset;
-
- /* Initialise tile area */
- memset(ret_tileset_ptr, 0, flex_size((flex_ptr)ret_tileset));
- ret_tileset_ptr->lasttile_num = max_tilenum;
-
- /* Scan sprite area */
- hourglass_on();
- {
- spriteareaheader *spritearea_ptr = *spritearea;
- spriteheader *input_sprite = (spriteheader *)((int)spritearea_ptr + spritearea_ptr->first);
-
- for(int sprite = 0; sprite < spritearea_ptr->sprite_count; sprite++) {
- hourglass_percentage((sprite * 100) / spritearea_ptr->sprite_count);
-
- /* Check source sprite header */
- char spritename[13];
- strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
- int tilenum = spritehdr_validtile(input_sprite, spritename);
- if(tilenum >= 0) {
- char *tile_data_end, *sprite_data_start;
-
- /* Calculate address of end of tile bitmap */
- tile_data_end = (char *)((int)ret_tileset_ptr + sizeof(SF_MapTilesSetHdr) + (tilenum * sizeof(SF_MapTile)) + sizeof(SF_MapTile));
-
- /* calculate address of start of sprite bitmap */
- sprite_data_start = (char *)((int)input_sprite + input_sprite->image);
-
- /* copy across raw bitmap */
- for(int row = 0; row < SF_MAPTILE_HEIGHT; row++) {
- /* notice that tile is reversed up/down during copying */
- /* eg row 0-row 3,row 1-row 2,row 2-row 1, row 3-row 0 */
- memcpy(
- (char *)(tile_data_end - ((row+1)*SF_MAPTILE_WIDTH)),
- (char *)(sprite_data_start + (row*SF_MAPTILE_WIDTH)),
- SF_MAPTILE_WIDTH
- );
- } /* next row of tile */
- }
- else {
- /* Invalid sprite header! */
- nobudge_deregister();
- hourglass_off();
-
- if(abandon_on_dud) {
- /* Abandon rest of file with error */
- err_report(255, msgs_lookup_sub1("BadSprite", spritename));
- flex_free((flex_ptr)ret_tileset);
- return false; /* failure */
- }
- if(!dialogue_confirm(msgs_lookup_sub1("BadSpriteCont", spritename))) {
- flex_free((flex_ptr)ret_tileset);
- return false; /* User wants to abandon rest of file */
- }
- else {
- /* User wants to skip sprite and continue */
- hourglass_on();
- nobudge_register(1024);
- }
- }
-
- /* Calculate address of next sprite */
- input_sprite = (spriteheader *)((int)input_sprite + input_sprite->size);
-
- } /* loop back (next sprite) */
- }
- hourglass_off();
-
- nobudge_deregister();
- return true; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- bool tiles_to_sprites(SF_MapTilesSetHdr **tileset, spriteareaheader **ret_sprarea) {
- /* finished 29/03/00
- re-written to flip tile up/down 10/07/2000
- Checks validity of Sprite area 19/07/2000
- 10.05.01 returns code indicating success
- 05.06.01 removed (excessive?) memory checking
- 16.09.01 areasize eliminated as a parameter - not needed if no checks
- 05.10.01 copied from SFtoSpr to SFeditor
- made parameters strongly typed and eliminated *outsize
- now returns an error block rather than 0 for fail
- 16.12.01 input and output blocks are both flexlib.
- 05.05.02 static pointers to flex blocks
- more scopes to help register allocation
- 20.11.02 eliminated floats from hourglass percentage calculation
- */
- int numtiles;
- spriteareaheader *ret_sprarea_ptr;
-
- /* read tile area details */
- numtiles = (*tileset)->lasttile_num + 1;
- if (numtiles < 0 || numtiles > 254)
- M_RETV("BadNumGFX", false)
-
- /* Allocate memory for sprite area */
- if(!flex_alloc((flex_ptr)ret_sprarea, sizeof(spriteareaheader) + ((sizeof(spriteheader)+sizeof(SF_MapTile))*numtiles)))
- MG_RETV("NoMem", false)
-
- nobudge_register(1024);
- ret_sprarea_ptr = *ret_sprarea;
-
- /* initialise sprite area header */
- {
- int size = flex_size((flex_ptr)ret_sprarea);
- ret_sprarea_ptr->size = size;
- ret_sprarea_ptr->sprite_count = numtiles;
- ret_sprarea_ptr->first = sizeof(spriteareaheader);
- ret_sprarea_ptr->used = size;
- }
-
- hourglass_on();
- {
- SF_MapTilesSetHdr *tileset_ptr = *tileset;
- for(int tile = 0; tile < numtiles; tile++) {
- spriteheader *sph;
- char *tile_data_end, *sprite_data_start;
-
- hourglass_percentage((tile * 100) / numtiles);
-
- /* initialise header of new sprite */
- sph = (spriteheader *)( (int)ret_sprarea_ptr + sizeof(spriteareaheader) + (tile * (sizeof(spriteheader) + sizeof(SF_MapTile)) ) ); /* start of sprite */
- sph->size = sizeof(spriteheader) + sizeof(SF_MapTile);
- memset(sph->name, 0, sizeof(sph->name));
- sprintf(sph->name, "tile_%d", tile);
- sph->width = (SF_MAPTILE_WIDTH / 4) - 1;
- sph->height = SF_MAPTILE_HEIGHT - 1;
- sph->left_bit = 0;
- sph->right_bit = 31;
- sph->image = sizeof(spriteheader);
- sph->mask = sizeof(spriteheader);
- if(output_new_format)
- sph->type = OUTPUT_TYPE_NEW; /* New-style sprite type */
- else
- sph->type = OUTPUT_TYPE_MODE; /* old-style mode number */
-
- /* calculate address of end of tile bitmap */
- tile_data_end = (char *)( (int)tileset_ptr + sizeof(SF_MapTilesSetHdr) + (tile * sizeof(SF_MapTile)) + sizeof(SF_MapTile) ); /* start of tile */
-
- /* calculate address of start of sprite bitmap */
- sprite_data_start = (char *)( (int)sph + sizeof(spriteheader)); /* start of sprite data */
-
- /* copy across raw bitmap */
- for(int row = 0; row < SF_MAPTILE_HEIGHT; row++) {
- /* notice that tile is reversed up/down during copying */
- /* eg row 0-row 3,row 1-row 2,row 2-row 1, row 3-row 0 */
- memcpy(
- (char *)(sprite_data_start + (row * SF_MAPTILE_WIDTH)),
- (char *)(tile_data_end - ((row+1) * SF_MAPTILE_WIDTH)),
- SF_MAPTILE_WIDTH
- );
- } /* next row of tile */
-
- } /* loop back (next tile) */
- }
-
- if(verify_spriteareas) {
- /* Verify the sprite area that we have created */
- if(E(_swix(OS_SpriteOp, _INR(0,1), SPRITEOP_VERIFY_AREA + SPRITEOP_USERAREA_SPRNAME, ret_sprarea_ptr))) {
- flex_free((flex_ptr)ret_sprarea);
- return false; /* fail */
- }
- }
- hourglass_off();
-
- nobudge_deregister();
- return true; /* success */
- }
-
- /*
- Routines read/write planet file FORMAT IV
- e.g. mask and X,Y paint coordinates are obsolete
- */
-
- bool sprites_to_planets(spriteareaheader **spritearea, SF_PlanetsSetHdr **ret_planetset, bool abandon_on_dud)
- {
- /*
- 04.05.01 First version from sprites_to_tiles
- 10.05.01 Returns code indicating success
- New param 'abandon_on_dud' controls behaviour with dud sprites
- 11.06.01 Queries dud sprites during prescan, can create empty planets files
- 02.11.01 Copes properly with funny sized header on input sprite area
- Made parameters strongly typed
- 16.12.01 input and output blocks are both flexlib.
- 05.05.02 static pointers to flex blocks
- more scopes to help register allocation
- 20.11.02 eliminated floats from hourglass percentage calculation
- 05.09.03 fixed memory leak of ret_planetset on error
- */
-
- int max_planetnum;
- spriteareaheader *spritearea_ptr;
- SF_PlanetsSetHdr *ret_planetset_ptr;
-
- max_planetnum = get_max_planet_num(spritearea);
- if(max_planetnum == -1) /* indicates too many sprites */
- return false; /* failure */
-
- /* Allocate memory for planet set */
- if(!flex_alloc((flex_ptr)ret_planetset, sizeof(SF_PlanetsSetHdr) + (sizeof(SF_PlanetBitmap)*2*(max_planetnum+1))))
- MG_RETV("NoMem", false)
-
- nobudge_register(1024);
- spritearea_ptr = *spritearea;
- ret_planetset_ptr = *ret_planetset;
-
- /* Initialise planet set header */
- memset(ret_planetset_ptr, 0, flex_size((flex_ptr)ret_planetset));
- ret_planetset_ptr->lastplanet_num = max_planetnum;
- for(int i = 0; i < 2; i++) {
- ret_planetset_ptr->paintoffsets[i].xoffset=0;
- ret_planetset_ptr->paintoffsets[i].yoffset=0;
- ret_planetset_ptr->dataoffsets[i].dataoffset = sizeof(SF_PlanetsSetHdr) + (i*sizeof(SF_PlanetBitmap)*2);
- ret_planetset_ptr->dataoffsets[i].maskoffset = ret_planetset_ptr->dataoffsets[i].dataoffset + sizeof(SF_PlanetBitmap);
- }
-
- /* Scan sprite area */
- hourglass_on();
- {
- spriteheader *input_sprite = (spriteheader *)((int)spritearea_ptr + spritearea_ptr->first);
- for(int sprite = 0; sprite < spritearea_ptr->sprite_count; sprite++) {
- hourglass_percentage((sprite * 100) / spritearea_ptr->sprite_count);
-
- /* Check source sprite header */
- char spritename[13];
- strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
- int planetnum = spritehdr_validpla(input_sprite, spritename);
- if(planetnum >= 0) {
- /* Copy across raw bitmap */
- memcpy((void *)((int)ret_planetset_ptr + ret_planetset_ptr->dataoffsets[planetnum].dataoffset),
- (void *)((int)input_sprite + input_sprite->image),
- sizeof(SF_PlanetBitmap));
-
- /* And a pointless duplicate for backwards-compatibility */
- memcpy((void *)((int)ret_planetset_ptr + ret_planetset_ptr->dataoffsets[planetnum].maskoffset),
- (void *)((int)input_sprite + input_sprite->image),
- sizeof(SF_PlanetBitmap));
- }
- else {
- /* Invalid sprite header! */
- nobudge_deregister();
- hourglass_off();
-
- if(abandon_on_dud) {
- /* Abandon rest of file with error */
- err_report(255, msgs_lookup_sub1("BadSprite", spritename));
- flex_free((flex_ptr)ret_planetset);
- return false; /* failure */
- }
- if(!dialogue_confirm(msgs_lookup_sub1("BadSpriteCont", spritename))) {
- flex_free((flex_ptr)ret_planetset);
- return false; /* User wants to abandon rest of file */
- }
- else {
- /* User wants to skip sprite and continue */
- hourglass_on();
- nobudge_register(1024);
- }
- }
-
- /* Calculate address of next sprite */
- input_sprite = (spriteheader *)((int)input_sprite + input_sprite->size);
-
- } /* loop back (next sprite) */
- }
- hourglass_off();
-
- nobudge_deregister();
- return true; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- bool planets_to_sprites(SF_PlanetsSetHdr **planetsset, spriteareaheader **ret_sprarea)
- {
- /*
- 04.05.01 First version from BASIC converter and tiles_to_sprites
- 10.05.01 returns code indicating success
- 02.11.01 made parameters strongly typed and eliminated *outsize
- returns error block
- 17.12.01 input and output blocks are both flexlib.
- 05.05.02 static pointers to flex blocks
- more scopes to help register allocation
- 20.11.02 eliminated floats from hourglass percentage calculation
- */
- int numplanets;
- spriteareaheader *ret_sprarea_ptr;
- SF_PlanetsSetHdr *planetsset_ptr;
-
- /* read planets data details */
- numplanets = (*planetsset)->lastplanet_num+1;
- if (numplanets < 0 || numplanets > 2)
- M_RETV("BadNumGFX", false)
-
- {
- /* Allocate memory for sprite area */
- int outsize = sizeof(spriteareaheader) + ((sizeof(spriteheader) + sizeof(SF_PlanetBitmap)) * numplanets);
- if(!flex_alloc((flex_ptr)ret_sprarea, outsize))
- MG_RETV("NoMem", false)
-
- nobudge_register(1024);
- ret_sprarea_ptr = *ret_sprarea;
- planetsset_ptr = *planetsset;
-
- /* initialise sprite area header */
- ret_sprarea_ptr->size = outsize;
- ret_sprarea_ptr->sprite_count = numplanets;
- ret_sprarea_ptr->first = sizeof(spriteareaheader);
- ret_sprarea_ptr->used = outsize;
- }
-
- hourglass_on();
- for(int planet = 0; planet < numplanets; planet++) {
- spriteheader *sph;
-
- hourglass_percentage((planet * 100) / numplanets);
-
- /* initialise header of new sprite */
- sph = (spriteheader *)((int)ret_sprarea_ptr + sizeof(spriteareaheader) + (planet * (sizeof(spriteheader) + sizeof(SF_PlanetBitmap)))); /* start of sprite */
- sph->size = sizeof(spriteheader) + sizeof(SF_PlanetBitmap);
- memset(sph->name, 0, sizeof(sph->name));
- sprintf(sph->name, "planet_%d", planet);
- sph->width = (SF_PLANET_WIDTH/4)-1;
- sph->height = SF_PLANET_HEIGHT-1;
- sph->left_bit = 0;
- sph->right_bit = 31;
- sph->image = sizeof(spriteheader);
- sph->mask = sizeof(spriteheader);
- if(output_new_format)
- sph->type = OUTPUT_TYPE_NEW; /* New-style sprite type */
- else
- sph->type = OUTPUT_TYPE_MODE; /* old-style mode number */
-
- /* copy across raw bitmap */
- memcpy((void *)((int)sph + sizeof(spriteheader)),
- (void *)((int)planetsset_ptr + planetsset_ptr->dataoffsets[planet].dataoffset),
- sizeof(SF_PlanetBitmap));
-
- } /* loop back (next planet) */
-
- if(verify_spriteareas) {
- /* Verify the sprite area that we have created */
- if(E(_swix(OS_SpriteOp, _INR(0,1), SPRITEOP_VERIFY_AREA + SPRITEOP_USERAREA_SPRNAME, ret_sprarea_ptr))) {
- flex_free((flex_ptr)ret_sprarea);
- return false; /* fail */
- }
- }
- hourglass_off();
-
- nobudge_deregister();
- return true; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
- /* Private functions */
-
- static int check_spr_type(int type)
- {
- /* Check that sprite type specifies 256 colours */
- return (type == 10 /* Old sprite format, 8bpp mode numbers... */
- || type == 13
- || type == 15
- || type == 21
- || type == 24
- || type == 28
- || type == 32
- || type == 36
- || type == 40
- || type>>27 == 4); /* New sprite format, 8bpp */
- }
-